<template>
  <el-card>
    <div class="card-header">
      <span>Api管理</span>
    </div>
  </el-card>
  <el-card class="content">
    <el-form-item>
      <perms-button
          perms="privilege:api:list"
          :type="Types.primary"
          :plain="true"
          @action="list"/>
    </el-form-item>
    <el-table
        v-if="tableVisible"
        :data="apiList"
        :border="true"
        row-key="id"
        :default-expand-all="expand"
        :tree-props="{ children: 'children', hasChildren: '!!children' }"
        class="table"
    >
      <template #empty>
        <el-empty/>
      </template>
      <el-table-column label="">
        <template #header>
          <perms-button
              perms="privilege:api:add"
              :type="Types.primary"
              :size="Sizes.default"
              :plain="true"
              @action="addApi"/>
          <el-button @click="switchExpand(true)" size="default">展开全部</el-button>
          <el-button @click="switchExpand(false)" size="default">折叠全部</el-button>
        </template>
        <el-table-column prop="name" label="Api名称" min-width="200">
          <template #default="scope">
            <el-link :icon="scope.row.icon">{{ scope.row.name }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="path" label="Api路径" min-width="160"/>
        <el-table-column prop="component" label="组件路径" min-width="160"/>
        <el-table-column prop="method" label="请求方法" width="90" align="center"/>
        <el-table-column prop="uri" label="请求路径" min-width="120"/>
        <el-table-column prop="perms" label="权限标识" min-width="160"/>
        <el-table-column prop="sort_id" label="排序" width="60" align="center"/>
        <el-table-column prop="type" label="类型" width="90" align="center">
          <template #default="scope">
            <el-tag size="small" :type="typeType(scope.row.type)">{{ typeText(scope.row.type) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="hidden" label="显示状态" width="90" align="center">
          <template #default="scope">
            {{ scope.row.hidden ? '隐藏' : '显示' }}
          </template>
        </el-table-column>
        <el-table-column label="备注" prop="remark" min-width="100"/>
        <el-table-column label="操作" min-width="160">
          <template #default="scope">
            <perms-link
                perms="privilege:api:add"
                :type="Types.primary"
                :plain="true"
                @action="addSubApi(scope.row)"/>
            <perms-link
                perms="privilege:api:update"
                :type="Types.warning"
                :plain="true"
                @action="editApi(scope.row)"/>
            <el-popconfirm
                :title="`确定删除Api[${scope.row.name}]吗?`"
                :icon="InfoFilled"
                icon-color="#F56C6C"
                cancel-button-text="取消"
                confirm-button-text="确认删除"
                cancel-button-type="info"
                confirm-button-type="danger"
                @confirm="deleteApi(scope.row.id)"
                width="300"
            >
              <template #reference>
                <perms-link
                    perms="privilege:api:delete"
                    :type="Types.danger"
                    :plain="true"/>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>

      </el-table-column>
    </el-table>
  </el-card>
  <el-dialog
      v-model="visible"
      :title="title"
      draggable
      width="800"
      :close-on-click-modal="false"
      @close="handleClose"
  >
    <el-form ref="formRef" :model="apiForm" :rules="rules" label-width="100">
      <el-row>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="上级Api" prop="parent_id">
            <el-cascader
                :options="options"
                :props="props"
                v-model="cascaderParent"
                ref="parentRef"
                clearable
                @change="handleParentChange"
                style="width: 360px">
              <template #default="{ node, data }">
                <span>{{ data.name }}</span>
                <span v-if="!node.isLeaf"> ({{ !!data.children ? data.children.length : 0 }}) </span>
              </template>
            </el-cascader>
          </el-form-item>
          <el-form-item label="Api名称" prop="name">
            <el-input v-model="apiForm.name" style="width: 360px" placeholder="例如：权限管理"/>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="Api类型" prop="type">
            <el-radio-group v-model.number="apiForm.type" :disabled="action==='editApi'">
              <el-radio :label="1">模块</el-radio>
              <el-radio :label="2">API</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="排序" prop="sort_id">
            <el-input v-model.number="apiForm.sort_id" style="width: 360px"/>
          </el-form-item>
        </el-col>
      </el-row>
      <el-divider/>
      <el-row>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="请求方法" prop="method">
            <el-select v-model="apiForm.method" :disabled="apiForm.type===1" autocomplete="off" clearable style="width: 360px">
              <el-option value="" label=" "/>
              <el-option label="GET" value="GET"/>
              <el-option label="POST" value="POST"/>
              <el-option label="PUT" value="PUT"/>
              <el-option label="PATCH" value="PATCH"/>
              <el-option label="DELETE" value="DELETE"/>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="请求路径" prop="path">
            <el-input v-model="apiForm.uri" :disabled="apiForm.type===1" style="width: 360px"/>
          </el-form-item>
        </el-col>
      </el-row>
      <el-form-item label="备注">
        <el-input v-model="apiForm.remark" type="textarea" rows="5" placeholder="请输入备注"></el-input>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" plain @click="handleSubmit">提交</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
//Api列表表单
import {nextTick, onMounted, reactive, ref} from "vue";
import {Api} from "@/interface/api";
import {ApiAddR, ApisR, ApiRemoveR, ApiUpdateR} from "@/api/api";
import {CascaderInstance, ElMessage, FormInstance, FormRules} from "element-plus";
import Node from "element-plus/es/components/cascader-panel/src/node";
import {InfoFilled} from "@element-plus/icons-vue";
import {LoadApiTree} from "@/utils/api";
import {Sizes, Types} from "@/interface/enum";
import PermsButton from '@/components/PermsButton.vue'
import PermsLink from '@/components/PermsLink.vue'
import {DeleteRequest} from "@/interface/user";

const initApiForm = () => {
  return <Api>{
    id: 0,
    type: 1,
    sort_id: 0,
    parent_id: 0,
    uri: '',
    method: '',
    name: '',
    remark: ''
  }
}

//级联选择器
const options = ref<Api[]>()
const props = ref({label: 'name', value: 'id', checkStrictly: true})

const apiForm = ref<Api>(initApiForm())
const iconList = ref<Array<string>>([])
const icon = ref<string>('search')
//表单校验
const formRef = ref<FormInstance>()
const parentRef = ref<CascaderInstance>()

//表格展开属性
const expand = ref<boolean>(false)
const tableVisible = ref<boolean>(true)

const apiList = ref<Api[]>()
//dialog可见
const visible = ref<boolean>(false)
const title = ref<string>('')
const action = ref<string>('') //表单动作：addApi，新增Api； addSubApi，新增子Api； editApi，修改Api

const rules = reactive<FormRules>({
  parent_id: [
    {required: true, message: '必填', type: "number", min:0, trigger: ['blur', 'change']}
  ],
  type: [
    {required: true, message: '请选择指定的Api类型', type: "enum", enum: [1, 2], trigger: ['blur', 'change']},
  ],
  name: [
    {required: true, message: '必填', type: "string", trigger: ['blur', 'change']}
  ],
  uri: [
    {required: true, message: '必填', type: "string", trigger: ['blur', 'change']}
  ],
  sort_id: [
    {required: true, message: '必填', type: "number", trigger: ['blur', 'change']}
  ],
})

const list = () => {
  ApisR().then(res => res.data).then(res => {
    switch (res.code) {
      case 200:
        //Api列表=>Api树
        let apis = res.data as Api[]
        let parents = apis.filter((m) => m.parent_id === 0)
        let children = apis.filter((m) => m.parent_id !== 0)

        LoadApiTree(parents, children)

        apiList.value = parents

        let api: Api = initApiForm()
        api.name = '主类目'
        api.children = parents
        options.value = [api]

        parentIds.value = new Map<number, Array<number>>()
        loadParentIds([api])
        break
      default:
        //ElMessage.error(res.msg)
    }
  })
}

//Api展开
const switchExpand = (val:boolean) =>{
  tableVisible.value=false
  expand.value = val

  nextTick(()=>{
    tableVisible.value=true
  })
}

const typeText = (val: number) => {
  switch (val) {
    case 1:
      return '模块'
    case 2:
      return 'API'
    default:
      console.log('未知Api类型：', val)
      return '未知'
  }
}

const typeType = (val: number) => {
  switch (val) {
    case 1:
      return 'success'
    case 2:
      return 'danger'
    default:
      return 'info'
  }
}


//获取Api节点的完整级联路径
const parentIds = ref<Map<number, Array<number>>>(new Map<number, Array<number>>())
const cascaderParent = ref<Array<number>>([])
const loadParentIds = (apis: Api[]) => {
  parentIds.value.set(0, [])
  apis.forEach((api) => {
    //查询上级Api的路径
    let parentId: Array<number> = []
    if (!parentIds.value.has(api.parent_id)) {
      parentIds.value.set(api.parent_id, [])
    }

    parentId = parentIds.value.get(api.parent_id) as Array<number>
    parentIds.value.set(api.id!, [...parentId, api.parent_id])
    // console.log('[id]', api.id, '=>[parent_id]', api.parent_id, '=> [path]', JSON.stringify(parentIds.value.get(api.id)))

    if (!!api.children && api.children.length > 0) {
      loadParentIds(api.children)
    }
  })
}

const handleParentChange = (value: Array<number>) => {
  console.log('上级Api变动：', value)
}

//添加Api
const addApi = () => {
  visible.value = true
  title.value = '新增Api'
  action.value = 'addApi'
  apiForm.value = initApiForm()
}


//添加子Api
const addSubApi = (parent: Api) => {
  title.value = '新增Api'
  action.value = 'addSubApi'
  visible.value = true
  apiForm.value = initApiForm()
  apiForm.value.parent_id = parent.id!
  cascaderParent.value = [...parentIds.value.get(parent.id!) as Array<number>, parent.id!]
}

//修改Api
const editApi = (api: Api) => {
  title.value = '修改Api'
  action.value = 'editApi'
  visible.value = true
  apiForm.value = JSON.parse(JSON.stringify(api))
  cascaderParent.value = parentIds.value.get(api.id!) as Array<number>
}

//提交表单
const handleSubmit = () => {
  //设置parent_id
  let nodes = parentRef.value?.getCheckedNodes(false) //是否只监测leaf节点
  // console.log('Api节点树：', nodes)
  if (!!nodes && nodes.length > 0) {
    apiForm.value.parent_id = (nodes.pop() as Node).value as number
  } else {
    apiForm.value.parent_id = 0
  }

  console.log('parent_id:', apiForm.value.parent_id)

  //表单校验
  formRef.value?.validate((isValid) => {
    if (!isValid) {
      return
    }

    switch (action.value) {
      case 'addApi':
        ApiAddR(apiForm.value).then(res => res.data).then((res) => {
          switch (res.code) {
            case 200:
              handleClose()
              list()
              break
            default:
          }
        })
        break
      case 'addSubApi':
        ApiAddR(apiForm.value).then(res => res.data).then(res => {
          switch (res.code) {
            case 200:
              handleClose()
              list()
              break
            default:
          }
        })
        break
      case 'editApi':
        ApiUpdateR(apiForm.value).then(res => res.data).then(res => {
          switch (res.code) {
            case 200:
              ElMessage.success(res.msg)
              handleClose()
              list()
              break
            default:
          }
        }).catch(err => {
          ElMessage.error(err.toString())
        })
        break
      default:
        ElMessage.warning('未知操作')
    }
  })
}

//删除Api
const deleteApi = (id: number) => {
  console.log('删除Api：', id)
  let req = <DeleteRequest>{id: id}
  ApiRemoveR(req).then(res => res.data).then(res => {
    switch (res.code) {
      case 200:
        ElMessage.success(res.msg)
        list()
        break
      default:
    }
  })
}

//关闭表单
const handleClose = () => {
  visible.value = false
  // formRef.value?.resetFields()
  apiForm.value = initApiForm()
}


onMounted(() => {
  list()
})

</script>

<style scoped lang="less">
.el-card {
  margin-bottom: 10px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.table{
  height: calc(100vh - 315px)
}

.page {
  margin-top: 10px;
}

.links {
  padding-right: 10px;
}

//图标气泡卡片
.icon-popper {
  max-height: 500px;
}

.icon-content {
  max-height: 450px;
  overflow: auto;
  overflow-x: hidden;
}
</style>